/* utilize the apu code to play spc files */

#include <iostream>
#include <fstream>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include "spcplayer.h"
#include "SNES_SPC.h"
#include "RIFF.h"

#define ALSA_PCM_NEW_HW_PARAMS_API
#define VERSION 0.05V

using namespace std;

int arg_parse(config* c, int argc, char *argv[]){
	//segregate out argument parsing for readability
	if(argc < 1) { return -1; }//argument validation test, FIXME
	int parse, r = 0;
	while ( (parse = getopt(argc, argv, "ho::t:") ) != -1){
		switch(parse){
			case 'h':
				printf("spcplayer [-h] [-o outfile] [-t seconds] file.spc");
				r = -1;
				break;
			case 'o':
				if (optarg == NULL) c->outfile = "out.wav";
				else c->outfile = optarg;
				c->dumpfile = true;
				break;
			case 't': c->duration = atoi(optarg); break;
			default: ;
		}
	}
	return r;
}

int main(int argc, char *argv[]){
	SNES_SPC* apu = new SNES_SPC; //this is the virtual apu
	config c; //I'm using a constructor
	RIFF r(32000, 2); //and again
	snd_pcm_t *pcm;
	char * song = NULL;
	short buf[64000]; //call an apu function to fill this with audio data
	//enough space for 1 second of audio

	if(arg_parse(&c, argc, argv) == -1) return 1; //parse commandline arguments

	//open the spc file
	ifstream in (argv[optind], std::ifstream::binary);
	if(!in.is_open()){
		//check to see if the input exists
		cout << "Problem with input." << endl;
		return 1;
	}

	cout << "Processing " << argv[optind] << endl;
	ofstream out (c.outfile, std::ofstream::binary);
	if (c.dumpfile) cout << "Outputting to " << c.outfile << endl;
	else cout << "Playing with ALSA" << endl;

	in.seekg(0, in.end); //seek to end
	if(in.fail())
		cout << "Failure Occured!" << endl;
	int size = in.tellg(); //get size
	in.seekg(0, in.beg); //rewind

	song = new char[size]; //make a spc sized buffer
	in.read(song, size); //read the spc file into memory

	cout << "Preparing APU" << endl;

	apu->init();
	apu->load_spc(song, size); //load an spc

	delete [] song; //free the memory

	cout << "Retrieving Samples" << endl;

	int i = 0;
	if(c.dumpfile){ //writing to file
		r.chunksize = c.duration * sizeof buf+36;
		r.subchunksize2 = c.duration * sizeof buf; //i do 1000ms buffering...
		out.write((char *) &r, sizeof r);
		do {
			apu->play(sizeof buf/2, buf); //fills a buffer with count stereo samples (so double the number of frames)
			out.write((char *) buf, sizeof buf); //cpp file access is so weird
		} while(++i <= c.duration);
	}
	else { //play the file through alsa
		snd_pcm_open(&pcm, "default",  SND_PCM_STREAM_PLAYBACK, 0);
		snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 2, 32000, 1, 500000);
		while(1){
			apu->play(sizeof buf/2, buf);
			i = snd_pcm_writei(pcm, buf, 32000);
			if(i == -EPIPE){
				snd_pcm_prepare(pcm);
			}
		}
		snd_pcm_drain(pcm);
		snd_pcm_close(pcm);
	}

	in.close();
	out.close();

	return 0; //for lack of a better return value
}
